#include <iostream>
// #include <string>
#include <memory>
#include <sys/select.h> // for select()
#include "Socket.hpp"

using namespace SockModule;
using namespace LogModule;

#define NR_FD sizeof(fd_set) * 8

const int default_fd = -1;

class SelectSvr
{
public:
    SelectSvr(uint16_t port)
        : _port(port), _listen_sock(std::make_unique<TcpSocket>())
    {
    }
    ~SelectSvr() {}

    void Init()
    {
        _listen_sock->BuildTcpSocket(_port);
        for (int i = 1; i < NR_FD; i++)
            _fd_array[i] = default_fd;
        _fd_array[0] = _listen_sock->Fd();
    }
    void Loop()
    {
        _isrunning = true;
        /* 先前的代码逻辑
        while (true)
        {
            InetAddr addr;
            // 之前的代碼 TcpSock accept 结构体 Accept 也是一种 IO模型,默认为阻塞式
            // 现在我们需要 将IO 设置成  多路转接模式   Multiplying
            int newsock = _listen_sock->Accepter(&addr);
        }
        */
        // select 代码逻辑
        fd_set rfds;

        while (_isrunning)
        {

            FD_ZERO(&rfds);
            int maxfd = default_fd;
            for (int i = 0; i < NR_FD; i++)
            {
                if (_fd_array[i] == default_fd)
                    continue;
                // 合法的fd
                FD_SET(_fd_array[i], &rfds); // 包含listensockfd
                // 更新出最大值
                if (maxfd < _fd_array[i])
                {
                    maxfd = _fd_array[i];
                }
            }
            

            // struct timeval timeout = {0,0};
            struct timeval timeout = {10, 0};

            int n = select(maxfd + 1, &rfds, nullptr, nullptr, &timeout);
            switch (n)
            {
            case 0:
                std::cout << "timeout ..." << std::endl;
                break;
            case -1:
                perror("select: ");
                break;
            default:
                std::cout << "IO affair ready." << std::endl;
                Dispatcher(rfds);
                break;
            }
        }

        _isrunning = false;
    }
    void Accepter()
    {
        InetAddr client;
        int n = _listen_sock->Accepter(&client);
        if(n < 0)
            return;

        std::cout << "获得了一个新的链接: " << n << " client info: " << client.Addr() << std::endl;
        int pos = -1;
        for(int i = 0; i < NR_FD; ++i){
            LOG(LogLevel::DEBUG) << "Accepter: POS:" << pos;
            LOG(LogLevel::DEBUG) << "Accepter: _fd_array:" << i << " " << _fd_array[i];
            if(_fd_array[i] == default_fd){
                pos = i;
                break;
            }
        }
        if(pos == default_fd){
            LOG(LogLevel::ERROR) << "服务器繁忙";
            close(n);
        }
        // 空位找到
        else{
            _fd_array[pos] = n;
        }
    }
    void Recever(int index)
    {
        char buffer[1024];
        ssize_t n = recv(_fd_array[index], buffer, sizeof(buffer) - 1, 0);
        if(n > 0){
            buffer[n] = 0;
            std::cout << "client# " << buffer << std::endl;
            // 回显
            std::string msg = "echo# ";
            msg += buffer;
            send(_fd_array[index], msg.c_str(), msg.size(), 0); // bug
        }
        else if(n == 0){
            // 远端关闭
            LOG(LogLevel::DEBUG) << "客户端退出, sockfd: " << _fd_array[index];
            close(_fd_array[index]);
            // 复原
            _fd_array[index] = default_fd;
        }
        else{
            LOG(LogLevel::DEBUG) << "客户端读取出错, sockfd: " << _fd_array[index];
            close(_fd_array[index]);
            _fd_array[index] = default_fd;
        }
    }
    void Dispatcher(fd_set &rfds)
    {
        for(int i = 0; i < NR_FD; ++i){
            if(_fd_array[i] == default_fd){
                continue;
            }
            // 合法的fd
            if(_fd_array[i] == _listen_sock->Fd()){
                // listen_sockfd
                if(FD_ISSET(_fd_array[i], &rfds)){
                    Accepter();
                }
            }
            else {
                if(FD_ISSET(_fd_array[i], &rfds)){
                    Recever(i);
                }
            }

        }
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listen_sock;
    bool _isrunning;
    int _fd_array[NR_FD];
};
